package cn.iocoder.yudao.module.wms.service.otherin;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.ApproveStatusEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.wms.dal.dataobject.doc.DocDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.otherin.OtherInDDO;
import cn.iocoder.yudao.module.wms.dal.mysql.otherin.OtherInDMapper;
import cn.iocoder.yudao.module.wms.service.doc.DocService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import cn.iocoder.yudao.module.wms.controller.admin.otherin.vo.*;
import cn.iocoder.yudao.module.wms.dal.dataobject.otherin.OtherInDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.wms.dal.mysql.otherin.OtherInMapper;

import javax.annotation.Resource;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;

/**
 * 通用入库单 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class OtherInServiceImpl implements OtherInService {

    @Resource
    private OtherInMapper otherInMapper;
    @Resource
    private OtherInDMapper otherInDMapper;
    @Resource
    private Map<String, OtherInStatusAbstract> map;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private DocService docService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOtherIn(OtherInSaveReqVO createReqVO) {
        // 校验
        validateOtherInCodeExists(null, createReqVO.getCode());
        // 插入
        OtherInDO otherIn = BeanUtils.toBean(createReqVO, OtherInDO.class);
        // 统计合计数量与合计金额
        BigDecimal businessSumQty = BigDecimal.ZERO;
        BigDecimal costSumAmt = BigDecimal.ZERO;
        for (int i = 0; i < createReqVO.getOtherInDs().size(); i++) {
            OtherInDDO otherInD = createReqVO.getOtherInDs().get(i);
            otherInD.setCostAmt(otherInD.getBusinessQty().multiply(otherInD.getUnitAmt()));
            otherInD.setSequence(i+1);
            costSumAmt = costSumAmt.add(otherInD.getCostAmt());
            businessSumQty = businessSumQty.add(otherInD.getBusinessQty());
        }
        otherIn.setBusinessSumQty(businessSumQty);
        otherIn.setCostSumAmt(costSumAmt);
        // 登记表
        transactionTemplate.execute(status -> {
            otherInMapper.insert(otherIn);
            // 插入子表
            createOtherInDList(otherIn.getId(), createReqVO.getOtherInDs());
           return Boolean.TRUE;
        });
        //判断单据性质是否需要自动审核
        DocDO doc = docService.getDoc(otherIn.getDocId());
        if (doc.getAutoApprove().equals(CommonStatusEnum.ENABLE.getStatus())) {
            this.approveOtherIn(otherIn.getId());
        }
        // 返回
        return otherIn.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOtherIn(OtherInSaveReqVO updateReqVO) {
        // 校验
        validateOtherInAllowChange(updateReqVO.getId());
        validateOtherInCodeExists(updateReqVO.getId(), updateReqVO.getCode());
        // 统计合计数量与合计金额
        BigDecimal businessSumQty = BigDecimal.ZERO;
        BigDecimal costSumAmt = BigDecimal.ZERO;
        for (int i = 0; i < updateReqVO.getOtherInDs().size(); i++) {
            OtherInDDO otherInD = updateReqVO.getOtherInDs().get(i);
            otherInD.setCostAmt(otherInD.getBusinessQty().multiply(otherInD.getUnitAmt()));
            otherInD.setSequence(i+1);
            costSumAmt = costSumAmt.add(otherInD.getCostAmt());
            businessSumQty = businessSumQty.add(otherInD.getBusinessQty());
        }
        updateReqVO.setBusinessSumQty(businessSumQty);
        updateReqVO.setCostSumAmt(costSumAmt);
        // 更新
        OtherInDO updateObj = BeanUtils.toBean(updateReqVO, OtherInDO.class);
        otherInMapper.updateById(updateObj);
        // 更新子表
        updateOtherInDList(updateReqVO.getId(), updateReqVO.getOtherInDs());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOtherIn(Long id) {
        // 校验
        validateOtherInAllowChange(id);
        // 删除
        otherInMapper.deleteById(id);

        // 删除子表
        deleteOtherInDByHeadId(id);
    }

    private OtherInDO validateOtherInExists(Long id) {
        OtherInDO otherIn = otherInMapper.selectById(id);
        if (ObjectUtil.isEmpty(otherIn)) {
            throw exception(OTHER_IN_NOT_EXISTS);
        }
        return otherIn;
    }

    private void validateOtherInCodeExists(Long id, String code) {
        OtherInDO otherIn = otherInMapper.selectByCode(code);
        if (ObjectUtil.isEmpty(otherIn)) {
            return;
        }
        if (ObjectUtil.isEmpty(id)) {
            throw exception(OTHER_IN_CODE_EXISTS);
        }
        if (!id.equals(otherIn.getId())) {
            throw exception(OTHER_IN_CODE_EXISTS);
        }
    }

    private void validateOtherInAllowChange(Long id) {
        OtherInDO otherIn = validateOtherInExists(id);
        if (otherIn.getApproveStatus()) {
            throw exception(OTHER_IN_NOT_ALLOW_CHANGE);
        }
    }

    @Override
    public OtherInDO getOtherIn(Long id) {
        return otherInMapper.selectById(id);
    }

    @Override
    public PageResult<OtherInDO> getOtherInPage(OtherInPageReqVO pageReqVO) {
        return otherInMapper.selectPage(pageReqVO);
    }

    @Override
    public void approveOtherIn(Long id) {
        // 获取单据信息
        OtherInDO otherIn = validateOtherInExists(id);
        // 获取单身信息
        List<OtherInDDO> otherInDs = getOtherInDListByHeadId(id);
        map.get(otherIn.getApproveStatus().toString()).approve(otherIn, otherInDs);
    }

    @Override
    public void cancelOtherIn(Long id) {
        // 获取单据信息
        OtherInDO otherIn = validateOtherInExists(id);
        // 获取单身信息
        List<OtherInDDO> otherInDs = getOtherInDListByHeadId(id);
        map.get(otherIn.getApproveStatus().toString()).cancel(otherIn, otherInDs);
    }

    // ==================== 子表（通用入库单身） ====================

    @Override
    public List<OtherInDDO> getOtherInDListByHeadId(Long headId) {
        return otherInDMapper.selectListByHeadId(headId);
    }

    private void createOtherInDList(Long headId, List<OtherInDDO> list) {
        validateOtherInDExists(list);
        list.forEach(o -> o.setHeadId(headId));
        otherInDMapper.insertBatch(list);
    }

    private void updateOtherInDList(Long headId, List<OtherInDDO> list) {
        validateOtherInDExists(list);
        deleteOtherInDByHeadId(headId);
		list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createOtherInDList(headId, list);
    }

    private void deleteOtherInDByHeadId(Long headId) {
        otherInDMapper.deleteByHeadId(headId);
    }

    private void validateOtherInDExists(Collection<OtherInDDO> list) {
        if (CollectionUtil.isEmpty(list)) {
            throw exception(OTHER_IN_D_NOT_EXISTS);
        }
    }

}